﻿#-*- coding: utf-8 -*-

from gluon.tools import *
#SQLFORM,Mail, Auth, Crud, XML ,DEFAULT
#DEFAULT = lambda : None 

IDENT=lambda x,_:x

class IS_BOOL:
	def __init__(self,error_message='Tak albo nie!'):
		self.e=error_message
	def __call__(self,value):
		if value=='on' or value==False:
			return (value=='on',None)
		return (value,self.e)
	def formatter(self,value):
		return ['NIE','TAK'][value]

def WAL_FAIL(tekst):
	return IS_EXPR('0',error_message=tekst)

def url_pokaz_pracownika(record):
	return 'pokaz?id=%s' % record.id

def url_usun_pracownika(record):
	return 'usun?id=%s' % record.id

def url_modyfikuj_pracownika(record):
	return 'modyfikuj?id=%s' % record.id

link_usun=('','usuń',url_usun_pracownika)
link_modyfikuj=('','modyfikuj',url_modyfikuj_pracownika)
link_pokaz=('','pokaż',url_pokaz_pracownika)

def url_pokaz(kontroler):
	def url_pokaz_cos(record):
		return URL(a='instytut',c=kontroler,f='pokaz?id=%s' % record.id)
	return url_pokaz_cos;


def url_grant_publikacje(record):
	return URL(a='instytut',c='publikacje',f='pokaz?id=%s' % record.id)

link_publikacja_pokaz=('','pokaż',url_pokaz('publikacje'))
link_grant_pokaz=('','pokaż',url_pokaz('granty'))

def wez_z_id(table,id,f=lambda x:x):
	"""
	Bierze nazwe tabeli oraz wartość id i zwraca f(T2(id=id))
	"""
	toprint = db[table][id]
	return f(toprint)

def id_wyswietlanie(field,record,f=lambda x: x):
	"""
	Bierze rekord i jego pole, które zawiera id do innej tabeli (T2) i zwraca f(T2(id=id))
	"""
	id = record[field.name]
	return wez_z_id(field.type[10:],id,f)

def jest_id(fields):
	return any(map(lambda f:f.type=='id',fields))
	
def wez_nazwa(rekord):
	if 'nazwa' in rekord:
		return rekord.nazwa
	else:
		return rekord.id
		
def wez_imie_nazwisko(rekord):
	if 'imie' in rekord and 'nazwisko' in rekord:
		return rekord.imie + ' ' + rekord.nazwisko
	return rekord.id

def wez_tytul(rekord):
	if 'tytul' in rekord:
		return rekord.tytul
	else :
		return rekord.id

def mapuj_stale(lista):
	def wez(rekord):
		if rekord.id<len(lista):
			return lista[rekord.id]
		else:
			return rekord.id
	return wez

def przepisz_wartosc(jaka,gdzie):
	def przep(request_vars,wpiszdo):
		if jaka in request_vars:
			request_vars[gdzie]=request_vars[jaka]
			wpiszdo[gdzie]=request_vars[jaka]
		return request_vars
	return przep
	
def mod_form_walidator_a_mniejsze_b(a,b):
	def tmp(form):
		str1=znajdz_zmien_obiekt_SQLFORM(a,form,lambda x: x)
		str2=znajdz_zmien_obiekt_SQLFORM(b,form,lambda x: x)
		walidator_a_mniejsze_b(str1,str2)
	return tmp

def mod_form_walidator_jedno_niepuste(a,b):
	def tmp(form):
		str1=znajdz_zmien_obiekt_SQLFORM(a,form,lambda x: x)
		str2=znajdz_zmien_obiekt_SQLFORM(b,form,lambda x: x)
		walidator_jedno_niepuste(str1,str2)
	return tmp
	
def mod_form_dodawaj_atrybuty(a,lista):
	def tmp(form):
		str=znajdz_zmien_obiekt_SQLFORM(a,form,lambda x: x)
		ustaw_atrybuty(str,lista)
	return tmp
		
def ustaw_atrybuty(pole,lista):
	for (n,w) in lista:
		pole.attributes[n]=w
	
def walidator_jedno_niepuste(pole1,pole2):
	wart1=wartosc_zmiennej_pola(pole1)
	wart2=wartosc_zmiennej_pola(pole2)
	if wart1=='' and wart2=='': 
		dodaj_walidator(pole1,WAL_FAIL('Jedno z pól musi być niepuste.'))
		dodaj_walidator(pole2,WAL_FAIL('Jedno z pól musi być niepuste.'))

def wartosc_zmiennej_pola(pole):
	wart=''
	if request.vars.has_key(pole.attributes['_name']): wart=request.vars[pole.attributes['_name']]
	return wart
	
def walidator_a_mniejsze_b(pole1,pole2):
	wart1=wartosc_zmiennej_pola(pole1)
	wart2=wartosc_zmiennej_pola(pole2)
	dodaj_walidator(pole1,IS_EXPR('not str(%(do)s).isdigit() or value<=(%(do)s)' % {'do':wart2}, error_message='Podana liczba jest za duża'))
	dodaj_walidator(pole2,IS_EXPR('not str(%(do)s).isdigit() or value>=(%(do)s)' % {'do':wart1}, error_message='Podana liczba jest za mała'))

def dodaj_walidator(pole,walidator):
	if not pole.attributes['requires']: pole.attributes['requires']=[]
	if not isinstance(pole.attributes['requires'],list): pole.attributes['requires']=[pole.attributes['requires']]
	pole.attributes['requires'].append(walidator)


def dodaj_wyglad_pola(pole,start):
	start.attributes['_class']=pole.type
	start.attributes['_id']=pole.name+'tmp'
	#start.attributes['_name']=pole.name+'tmp'
	requires=[]
	if pole.requires: 
		if isinstance(pole.requires,list):
			requires+=pole.requires
		else:
			requires+=[pole.requires]
	
	if start.attributes.has_key('requires'):
		if isinstance(start.attributes['requires'],list):
			requires+=start.attributes['requires']
		else:
			requires+=[start.attributes['requires']]
	start.attributes['requires']=requires
	return (pole.label,start)
	
def przechodz(akt, nazwa, funkcja):
	if isinstance(akt,DIV):
		if akt.attributes and akt.attributes.has_key('_name'):
			if akt.attributes['_name']==nazwa:
				return funkcja(akt)
		else:
			#if hasattr(akt,'__iter__') or hasattr(akt,'__getitem__'):
			for k in akt:
				wyn=przechodz(k,nazwa,funkcja)
				if wyn!=False:
					return wyn
	return False
	
def znajdz_zmien_obiekt_SQLFORM(nazwa,form,funkcja):
	tmp=form.components[0]
	return przechodz(tmp,nazwa,funkcja)
	
def wczytaj_jesli_pierwszy(formname,lista):
	if request.vars._formname!='publikacje':
		for (co, skad) in lista:
			co[1].attributes['_value']=skad
	
class ProfessorsSQLTABLE(SQLTABLE): 

	""" 
	given a SQLRows object, as returned by a db().select(), generates 
	an html table with the rows. 

	optional arguments: 
	linkto: URL to edit individual records 
	upload: URL to download uploaded files 
	orderby: Add an orderby link to column headers. 
	headers: dictionary of headers to headers redefinions 
	truncate: length at which to truncate text in table cells. 
			  Defaults to 16 characters. 
	optional names attributes for passed to the <table> tag 
	""" 
	"""
	linki mają postać (tytul,nazwa,f:rekord->link) dodawaj przyciski z taką akcją
	"""

	def __init__( 
		self, 
		sqlrows,
		style='ForrestTable',
		linkto=None, 
		upload=None, 
		orderby=None,
		show_id=0,
		headers={}, 
		truncate=16,
		map_id_napis={},
		linki=[], 
		**attributes 
		): 
		attributes['_class']=style
		TABLE.__init__(self,**attributes) 
		self.components = [] 
		self.attributes = attributes 
		self.sqlrows = sqlrows 
		(components, row) = (self.components, [])
		
		for c in sqlrows.colnames:
			(tablename, fieldname) = c.split('.') 
			field = sqlrows._db[tablename][fieldname] 
			
			if not c in headers: 
				(tablename, fieldname) = c.split('.') 
				headers[c]=db[tablename][fieldname].label
				
			if not (field.type=='id' and show_id==0):
				if not orderby: 
					row.append(TH(headers.get(c, c))) 
				else:
					row.append(TH(A(headers.get(c, c), _href='?orderby=' + c)))
					
		for (tytul,_,_) in linki:
			row.append(TH(tytul)) 
			
		components.append(THEAD(TR(*row))) 
		tbody = [] 
		
		for (rc, record) in enumerate(sqlrows): 
			row = [] 
			if rc % 2 == 0: 
				_class = 'even' 
			else: 
				_class = 'odd' 
			for colname in sqlrows.colnames:
				if not table_field.match(colname): 
					r = record._extra[colname] 
					row.append(TD(r)) 
					continue 
				(tablename, fieldname) = colname.split('.') 
				field = sqlrows._db[tablename][fieldname] 
				if record.has_key(tablename) and isinstance(record, 
						SQLStorage) and isinstance(record[tablename], 
						SQLStorage): 
					r = record[tablename][fieldname] 
				elif record.has_key(fieldname): 
					r = record[fieldname] 
				else: 
					raise SyntaxError, 'something wrong in SQLRows object' 
				
				
				
				#jesli id to nie wyswietlaj
				if field.type=='id' and show_id==0: continue
				
				if field.represent: 
					print 'represent'
					r = field.represent(r) 
					row.append(TD(r)) 
					continue 
				if field.type == 'blob' and r: 
					row.append(TD('DATA')) 
					continue 
				
				#jeśli referencja i mozesz to mapuj
				if field.type[:9] == 'reference': 
					#jeśli nie ma wartosci wpisz brak
					if not r: 
						r='brak'
					elif field.name in map_id_napis :
						r=id_wyswietlanie(field,record,map_id_napis[field.name])
				
				if field.type=='boolean':
					if r: r='Tak'
					else: r='Nie'
				else:
					r = str(field.formatter(r)) 
				if upload and field.type == 'upload' and r != None: 
					if r: 
						row.append(TD(A('file', _href='%s/%s' 
									% (upload, r)))) 
					else: 
						row.append(TD()) 
					continue 
				ur = unicode(r, 'utf8') 
				if len(ur) > truncate: 
					r = ur[:truncate - 3].encode('utf8') + '...' 
				#jeśli jest to id to sprawdz czy co masz wypisać
				# nie dawaj linkow na razie
				#if linkto and field.type == 'id': 
				#	row.append(TD(A(r, _href='%s/%s/%s' % (linkto, 
				#			   tablename, r)))) 
				#if linkto and field.type[:9] == 'reference': 
				#	row.append(TD(A(r, _href='%s/%s/%s' % (linkto, 
				#			   field.type[10:], r)))) 
				#else: 
				row.append(TD(r)) 
				
				#jeśli są dodawaj linki
			for (_,nazwa,funkcja) in linki:
				row.append(TD(A(nazwa, _href='%s' % funkcja(record)))) 
			tbody.append(TR(_class=_class, *row)) 
		components.append(TBODY(*tbody))



class ProfessorsSQLFORM(SQLFORM):
	def __init__( 
		self, 
		table, 
		record=None, 
		deletable=False, 
		linkto=None, 
		upload=None, 
		fields=None, 
		labels=None, 
		col3={}, 
		submit_button='Wyslij', 
		delete_label='Zaznacz by usun¹æ:', 
		showid=True, 
		readonly=False, 
		comments=True, 
		keepopts=[], 
		ignore_rw=False, 
		readonly_fields=[],
		map_id_napis={},
		modyfikuj_wpisane=[IDENT],
		implicit=[],
		modyfikuj_formularz=[],
		**attributes
		): 
		# dodano atrybut readonly_field który sprawia, że wypisane pola są tylko do odczytu
		nbsp=XML('&nbsp;') # Firefox2 does not display fields with blanks 
		ofields=fields 
		
		self.modyfikuj_wpisane=modyfikuj_wpisane
		if fields == None: 
			fields = [f for f in table.fields if ignore_rw or table[f].writable or table[f].readable]
		
		self.fields_writeable=filter(lambda field : field not in readonly_fields,fields)
		FORM.__init__(self, fields=self.fields_writeable,*[], **attributes) 
		
		self.fields = fields
		if not 'id' in self.fields: 
			self.fields.insert(0, 'id') 
		self.table = table 
		if record and isinstance(record, (int, long, str, unicode)): 
			records = table._db(table.id == record).select() 
			if records: 
				record = records[0] 
			else: 
				record = None 
		self.record = record 
		self.record_id = None 
		self.trows = {} 
		xfields = [] 
		self.fields=fields 
		self.custom=Storage() 
		self.custom.dspval=Storage() 
		self.custom.inpval=Storage() 
		self.custom.label=Storage() 
		for field in self.fields: 
			# podawane sa tylko nazwy, lub '(opis,pole formularza)'
			if not isinstance(field,str):
				#jeśli sztucznie dodany
				(nazwa,pole)=field
				label = LABEL(nazwa, _for=nazwa, _id='%s__label' % nazwa) 
				xfields.append(TR(label, pole, '', id=nazwa) ) 
				continue
			
			
			fieldname=field
			if fieldname.find('.') >= 0: 
				continue 
			
			field = self.table[fieldname] 
			if comments: 
				comment = col3.get(fieldname, field.comment) or '' 
			else: 
				comment = '' 
			if labels != None and labels.has_key(fieldname): 
				label = labels[fieldname] 
			else: 
				label = str(field.label) + ': ' 
			self.custom.label[fieldname]=label 
			field_id = '%s_%s' % (table._tablename, fieldname) 
			label = LABEL(label, _for=field_id, _id='%s__label' % field_id) 
			row_id = field_id + '__row' 
			if fieldname == 'id': 
				self.custom.dspval.id=nbsp 
				self.custom.inpval.id='' 
				if record: 
					if showid and 'id' in fields and field.readable: 
						v=record['id'] 
						self.custom.dspval.id=str(v) 
						xfields.append(TR(label, SPAN(v,_id=field_id),  
						comment, _id='id__row')) 
					self.record_id = str(record['id']) 
				continue 
			if record: 
				default = record[fieldname] 
			else: 
				default = field.default 
			cond = fieldname in readonly_fields or readonly or (not ignore_rw and not field.writable and field.readable) 
			if default and not cond: 
				default = field.formatter(default) 
			dspval=default 
			inpval=default 
			
			if cond: 
				# ## if field.represent is available else 
				# ## ignore blob and preview uploaded images 
				# ## format everything else 
				# jeśli jest rekord i pole to referencja to wyświetl to do zwroci map_id_napis
				
				#jeśli nie ma wartosci wpisz brak
				if field.type[:9] == 'reference' and not default: default='brak'
				
				if record and field.type[:9] == 'reference': 
					if field.name in map_id_napis:
						inp = field.formatter(id_wyswietlanie(field,record,map_id_napis[field.name]))
					#elif field.has_key('nazwa'):
					#	inp = field.formatter(id_wyswietlanie(field,record,map_id_napis[field.name]))
					elif OptionsWidget.has_options(field):
						opcje = field.requires.options() 
						wybrana=filter(lambda (k,l) : k==str(default),opcje)
						if default and len(wybrana)>0:
							inp = field.formatter(wybrana[0][1])
						else:
							inp = field.formatter('')
				elif field.represent: 
					inp = field.represent(default) 
				elif field.type in ['blob']: 
					continue 
				elif field.type == 'upload': 
					inp = UploadWidget.represent(field, default, upload) 
				else: 
					inp = field.formatter(default) 
			elif hasattr(field, 'widget') and field.widget: 
				inp = field.widget(field, default) 
			elif field.type == 'upload': 
				inp = self.widgets.upload.widget(field, default, upload) 
			elif field.type == 'boolean': 
				inp = self.widgets.boolean.widget(field, default) 
				if default: 
					inpval='checked' 
				else: 
					inpval='' 
			elif OptionsWidget.has_options(field): 
				if not field.requires.multiple: 
					inp = self.widgets.options.widget(field, default) 
				else: 
					inp = self.widgets.multiple.widget(field, default) 
				if fieldname in keepopts: 
					inpval=TAG[''](*inp.components) 
			elif field.type == 'text': 
				inp = self.widgets.text.widget(field, default) 
			elif field.type == 'password': 
				inp = self.widgets.password.widget(field, default) 
				if self.record: 
					dspval='********' 
				else: 
					dspval='' 
			elif field.type == 'blob': 
				continue 
			else: 
				if field.type == 'integer': # and isinstance(field.requires,list):
					if isinstance(field.requires,IS_INT_IN_RANGE):	
						field.requires.error_message='Musisz podać odpowiednią liczbę'
				if field.type == 'double': # and isinstance(field.requires,list):
					if isinstance(field.requires,IS_FLOAT_IN_RANGE):	
						field.requires.error_message='Musisz podać odpowiednią liczbę'
					#for val in field.requires:
					#	print 'jest',val
						#if isinstance(val,IS_INT_IN_RANGE):	
						#	print 'jest',val
						#	val.error_message='Musisz podać liczbę'
							
				inp = self.widgets.string.widget(field, default)
			
			tr = self.trows[fieldname] = TR(label, inp, comment, id=row_id) 
			xfields.append(tr) 

			if not fieldname in readonly_fields:
				self.custom.dspval[fieldname]=dspval or nbsp 
				self.custom.inpval[fieldname]=inpval or '' 
		#self.fields=self.fields_writeable
		if record and linkto: 
			for (rtable, rfield) in table._referenced_by: 
				query = urllib.quote(str(table._db[rtable][rfield]==record.id)) 
				lname = olname = '%s.%s' % (rtable, rfield) 
				if ofields and not olname in ofields: 
					continue 
				if labels and labels.has_key(lname): 
					lname = labels[lname] 
				xfields.append(TR('', A(lname, _class='reference', 
						_href='%s/%s?query=%s' % (linkto, 
						rtable, query)), col3.get(olname, '' 
						), _id='%s__row' % olname.replace('.' 
						, '__'))) 
		if record and deletable: 
			xfields.append(TR(LABEL(delete_label, _for='delete_record', 
					_id='delete_record__label'), 
					INPUT(_type='checkbox', _class='delete', 
					_id='delete_record', 
					_name='delete_this_record'), 
					col3.get('delete_record', ''), 
					_id='delete_record__row')) 
		if not readonly: 
			xfields.append(TR('', INPUT(_type='submit', 
				_value=submit_button), 
				col3.get('submit_button', ''), 
				_id='submit_record__row')) 
		if record: 
			if not self['hidden']: 
				self['hidden'] = {} 
			self['hidden']['id'] = record['id'] 

		self.components = [TABLE(*xfields)]
		for modyf in modyfikuj_formularz:
			modyf(self)
		
	def accepts( 
		self, 
		request_vars, 
		session=None, 
		formname='%(tablename)s', 
		keepvalues=False, 
		onvalidation=None, 
		):
		for fun in self.modyfikuj_wpisane:
			request_vars=fun(request_vars,self.vars)
		self.fields=self.fields_writeable
		wyn=SQLFORM.accepts(self,request_vars,session,formname,keepvalues,onvalidation)
		return wyn

class ProfessorsCrud(Crud):
	def __init__(self, environment, db): 
		Crud.__init__(self,environment,db)
		self.settings.submit_button = 'Wyslij' 
		self.settings.delete_label = 'Zaznacz by usun¹æ:' 

		self.settings.create_next = URL(a='instytut',c='home',f='komunikat', vars={'message': "Dodano pracownika"})
		self.settings.update_next = URL(a='instytut',c='home',f='komunikat', vars={'message': "Zmodyfikowano pracownika"})
		self.settings.delete_next = URL(a='instytut',c='home',f='komunikat', vars={'message': "Usunięto pracownika"})
		
		self.default_id_map = wez_nazwa

	def select( 
		self, 
		table,
		query=None, 
		fields=None, 
		orderby=None, 
		limitby=None, 
		headers={}, 
		id_map={},
		linki=[],
		**attr 
		): 
		request = self.environment.request 
		if isinstance(table, str): 
			if not table in self.db.tables: 
				raise HTTP(404) 
			table = self.db[table] 
		if not query: 
			query = table.id > 0 
		if not fields:
			fields = [table[nazwa] for nazwa in table.fields if nazwa != 'id']
			
		#jeśli nie ma id to dodaj (nie wyświetla id)
		#show_id=0 #nigdy nie wyswietlaj id
		if not jest_id(fields):
			show_id=0 # nie pokazuj bo dodany by miec id w rekordzie
			fields.insert(0,table.id)
		
		for k in fields:
			if not k.name in id_map:
				id_map[k.name]=self.default_id_map
		
		# jesli pole posiada labela to wyswietlaj go
		for c in fields:
			if isinstance(c,SQLField): headers[str(c._table) + '.' +str(c.name)]=c.label
				
		rows=self.db(query).select(*fields, **dict(orderby=orderby, limitby=limitby))
		
		if not attr.has_key('linkto'): 
			attr['linkto'] = URL(r=request, args='read') 
		if not attr.has_key('upload'): 
			attr['upload'] = URL(r=request, f='download') 
		
		if len(rows)==0:
			return 'brak'
		
		return ProfessorsSQLTABLE(rows, headers=headers, map_id_napis=id_map, linki=linki, **attr) 

	def update( 
        self, 
        table, 
        record, 
        next=DEFAULT, 
        onvalidation=DEFAULT, 
        onaccept=DEFAULT, 
        ondelete=DEFAULT, 
        log=DEFAULT, 
        message=DEFAULT, 
        deletable=DEFAULT,
		fields=None,
        readonly_fields=[],
		**attributes
        ): 
		request = self.environment.request 
		session = self.environment.session 
		if not request.vars._next: 
			request.vars._next = request.env.http_referer or '' 
		if next == DEFAULT: 
			next = self.settings.update_next or request.vars._next 
		if onvalidation == DEFAULT: 
			onvalidation = self.settings.update_onvalidation 
		if onaccept == DEFAULT: 
			onaccept = self.settings.update_onaccept 
		if ondelete == DEFAULT: 
			ondelete = self.settings.update_ondelete 
		if log == DEFAULT: 
			log = self.settings.update_log 
		if deletable == DEFAULT: 
			deletable = self.settings.update_deletable 
		if message == DEFAULT: 
			message = self.messages.record_updated 
		if isinstance(table, str): 
			if not table in self.db.tables: 
				raise HTTP(404) 
			table = self.db[table] 
		if not request.vars._next: 
			request.vars._next = request.env.http_referer or ''
		if not fields: 
			fields = table.fields
		
		form = ProfessorsSQLFORM(
			table, 
			record, 
			fields=fields,
			upload=URL(r=request, f='download'), 
			hidden=dict(_next=request.vars._next), 
			showid=self.settings.showid, 
			submit_button=self.settings.submit_button, 
			delete_label=self.settings.delete_label, 
			deletable=deletable,
			readonly_fields=readonly_fields,
			**attributes
		) 
		if form.accepts(request.vars, session, 
					onvalidation=onvalidation): 
			session.flash = message 
			log = self.settings.update_log 
			if log: 
				self.log_event(log % form) 
			if request.vars.delete_this_record and ondelete: 
				ondelete(form) 
			if onaccept: 
				onaccept(form) 
			if not next: 
				next = URL(r=request) 
			elif next and not next[0] == '/' and next[:4] != 'http': 
				next = URL(r=request, f=next.replace('[id]', 
					str(form.vars.id))) 
			redirect(next) 
		return form
	
	def update_publikacja():
		return ''

class ProfessorsIS_IN_DB(IS_IN_DB):
	 def __init__(self, dbset, field, label=None, map=None, **args):
		self.map=map
		IS_IN_DB.__init__(self,dbset,field,label=label,**args)
		
	 def options(self): 
		self.build_set()
		if self.map:
			return [(k, wez_z_id(self.ktable,k,self.map)) for (i, k) in enumerate(self.theset) if wez_z_id(self.ktable,k,self.map)!=''] 
		else:
			return [(k, self.labels[i]) for (i, k) in enumerate(self.theset)] 
